#define DOHOME_LOG_LVL          DOHOME_LOG_LVL_DEBUG
#define DOHOME_LOG_TAG          "hal_wifi"

#include "dohome_log.h"
// #include <dohome_product.h>
#include <dohome_hal_wifi.h>

#include "lwip/netif.h"
#include "lwip/dhcp.h"

#include <string.h>
#include "wm_include.h"
#include "tls_wireless.h"

DOHOME_STATIC dohome_wifi_mode_t _wf_mode = DOHOME_WIFI_MODE_LOWPOWER;
DOHOME_STATIC dohome_wifi_hal_event_t _wifi_event_status = DT_WIFI_EVENT_DISCONNECT;
DOHOME_STATIC dohome_wifi_event_cb_t _wifi_event_cb = NULL;
DOHOME_STATIC dohome_wifi_csan_cb_t _doit_wifi_csan_cb = NULL;

DOHOME_STATIC u8 dev_ip_str[16] = {0};

dohome_op_ret dohome_hal_wifi_get_ip(DOHOME_CONST dohome_wifi_if_t wf, dohome_net_ip_t *ip)
{
    /*u8 mac[6] = {0};
	int res = tls_get_mac_addr(mac);
	if (res == TLS_EFUSE_STATUS_OK) {
		ip_addr_t *ip_addr = tls_dhcps_getip(mac);
		sprintf(ip->ip, "%s", inet_ntoa(ip_addr->addr));
		return OPRT_OK;
	}*/
	//struct netif *netif = tls_get_netif(); 
	//sprintf(ip->ip, "%v", netif->ip_addr.addr);

	//sprintf(ip->ip, "%s", dev_ip_str);
	struct tls_ethif *ethif = tls_netif_get_ethif();
	DOHOME_LOG_I("my ip=%d.%d.%d.%d\n",  ip4_addr1(ip_2_ip4(&ethif->ip_addr)), ip4_addr2(ip_2_ip4(&ethif->ip_addr)),
           ip4_addr3(ip_2_ip4(&ethif->ip_addr)), ip4_addr4(ip_2_ip4(&ethif->ip_addr)));
	sprintf(ip->ip, "%d.%d.%d.%d", ip4_addr1(ip_2_ip4(&ethif->ip_addr)), ip4_addr2(ip_2_ip4(&ethif->ip_addr)),
           ip4_addr3(ip_2_ip4(&ethif->ip_addr)), ip4_addr4(ip_2_ip4(&ethif->ip_addr)));
    return OPRT_OK;
}


dohome_op_ret dohome_hal_wifi_get_mac(DOHOME_CONST dohome_wifi_if_t wf, dohome_net_mac_t *net_mac){
    int ret = 0;
    if (DOHOME_WIFI_IF_STATION == wf) {
		ret = tls_get_mac_addr(net_mac);
	} else if (DOHOME_WIFI_IF_SOFTAP == wf) {
		ret = tls_get_mac_addr(net_mac);
	}
	if (ret != TLS_EFUSE_STATUS_OK) {
		return ret;
	}
    return OPRT_OK;
}


dohome_op_ret dohome_hal_wifi_set_mode(DOHOME_CONST dohome_wifi_mode_t mode){
	switch (mode)
    {
        case DOHOME_WIFI_MODE_LOWPOWER:
        {
            // LOG_I("Low Power Mode");
            break;
        }
        case DOHOME_WIFI_MODE_STATION:
        {
            DOHOME_LOG_D("Station Mode");
            break;
        }
        case DOHOME_WIFI_MODE_SNIFFER:
        {
            DOHOME_LOG_D("Sniffer Mode");
            break;
        }

        case DOHOME_WIFI_MODE_SOFTAP:
        {
            DOHOME_LOG_D("SoftAp Mode");
            DOHOME_LOG_D("stop previous AP \r\n");
            break;
        }
        case DOHOME_WIFI_MODE_STATIONAP:
        {
            DOHOME_LOG_D("Station STA_AP Mode");
            break;
        }
    }

    _wf_mode = mode;
    return OPRT_OK;
}

dohome_wifi_mode_t dohome_hal_wifi_get_mode(void){
    return _wf_mode;
}

DOHOME_STATIC void apsta_demo_client_event(u8 *mac, enum tls_wifi_client_event_type event)
{
    printf("client %M is %s\r\n", mac, event ? "offline" : "online");
}
DOHOME_STATIC void apsta_demo_net_status(u8 status)
{
    struct netif *netif = tls_get_netif();

    switch(status)
    {
	case NETIF_WIFI_JOIN_SUCCESS:
        printf("NETIF_WIFI_JOIN_SUCCESS\n");
        break;
    case NETIF_WIFI_JOIN_FAILED:
        printf("sta join net failed\n");
        break;
    case NETIF_WIFI_DISCONNECTED:
        printf("sta net disconnected\n");
		_wifi_event_status = DT_WIFI_EVENT_DISCONNECT;
		if(_wifi_event_cb != NULL){
            _wifi_event_cb(DT_WIFI_EVENT_DISCONNECT, NULL);
        }
        break;
    case NETIF_IP_NET_UP:
        printf("\nsta ip: %v\n", netif->ip_addr.addr);
		memset(dev_ip_str, 0, 16);
		sprintf(dev_ip_str, "%v", netif->ip_addr.addr);
		_wifi_event_status = DT_WIFI_EVENT_CONNECT;
        if(_wifi_event_cb != NULL){
			_wifi_event_cb(DT_WIFI_EVENT_CONNECT, NULL);
        }
        _wifi_event_status = DT_WIFI_EVENT_GET_IP;
        if(_wifi_event_cb != NULL){
            _wifi_event_cb(DT_WIFI_EVENT_GET_IP, NULL);
        }
        break;
    case NETIF_WIFI_SOFTAP_FAILED:
        printf("softap create failed\n");
        break;
    case NETIF_WIFI_SOFTAP_CLOSED:
        printf("softap closed\n");
        break;
    case NETIF_IP_NET2_UP:
        printf("\nsoftap ip: %v\n", netif->next->ip_addr.addr);
        break;
    default:
        break;
    }
}

dohome_op_ret dohome_hal_wifi_ap_start(DOHOME_CONST dohome_wifi_cfg_if_t *cfg){
	tls_wifi_disconnect();
    tls_wifi_softap_destroy();

    tls_netif_add_status_event(apsta_demo_net_status);
    tls_wifi_softap_client_event_register(apsta_demo_client_event);

	struct tls_softap_info_t apinfo;
    struct tls_ip_info_t ipinfo;
    u8 ret = OPRT_OK;

    memset(&apinfo, 0, sizeof(apinfo));
    memset(&ipinfo, 0, sizeof(ipinfo));
	
	DOHOME_LOG_D("ap ssid :%s len, %d", cfg->ssid, cfg->s_len);

    if (cfg->ssid) {
        u8 ssid_len = cfg->s_len;
        MEMCPY(apinfo.ssid, cfg->ssid, ssid_len);
        apinfo.ssid[ssid_len] = '\0';
    } else {
		u8 *ssid = (u8 *)"w800_apsta_demo";
		u8 ssid_len = strlen("w800_apsta_demo");
        MEMCPY(apinfo.ssid, ssid, ssid_len);
        apinfo.ssid[ssid_len] = '\0';
    }

    apinfo.encrypt = strlen(cfg->passwd) ? IEEE80211_ENCRYT_CCMP_WPA2 : IEEE80211_ENCRYT_NONE;
    apinfo.channel = cfg->chan ? cfg->chan : 11; /*channel*/
    apinfo.keyinfo.format = 1; /*format:0,hex, 1,ascii*/
    apinfo.keyinfo.index = 1;  /*wep index*/
    apinfo.keyinfo.key_len = strlen(cfg->passwd); /*key length*/
    MEMCPY(apinfo.keyinfo.key, cfg->passwd, strlen(cfg->passwd));

    /*ip information:ip address,mask, DNS name*/
    ipinfo.ip_addr[0] = 192;
    ipinfo.ip_addr[1] = 168;
    ipinfo.ip_addr[2] = 4;
    ipinfo.ip_addr[3] = 1;
    ipinfo.netmask[0] = 255;
    ipinfo.netmask[1] = 255;
    ipinfo.netmask[2] = 255;
    ipinfo.netmask[3] = 0;
    MEMCPY(ipinfo.dnsname, "local.wm", sizeof("local.wm"));

    ret = tls_wifi_softap_create((struct tls_softap_info_t * )&apinfo, (struct tls_ip_info_t * )&ipinfo);
    return ret;
}

dohome_op_ret dohome_hal_wifi_ap_stop(void){
    tls_wifi_softap_destroy();
    return OPRT_OK;
}


void dohome_hal_wifi_set_event_cb(dohome_wifi_event_cb_t event_cb) {
    _wifi_event_cb = event_cb;
}

dohome_op_ret dohome_hal_wifi_station_connect(DOHOME_CONST DOHOME_CHAR_T *ssid, DOHOME_CONST DOHOME_CHAR_T *passwd){
	//struct tls_param_ip ip_param;
	tls_wifi_disconnect();
    tls_wifi_softap_destroy();

	tls_netif_add_status_event(apsta_demo_net_status);
	int ret = tls_wifi_connect((u8 *)ssid, strlen(ssid), (u8 *)passwd, strlen(passwd));
    if (WM_SUCCESS == ret) {
        DOHOME_LOG_I("\nplease wait connect net......\n");
		return OPRT_OK;
	} 

    DOHOME_LOG_I("\napsta connect net failed, please check configure......\n");
	return OPRT_COM_ERROR;
}

dohome_op_ret dohome_hal_wifi_station_disconnect(void){
    DOHOME_LOG_D("%s: sta disconnect\r\n", __func__);
	tls_wifi_disconnect();
    return OPRT_OK;
}

DOHOME_UINT8_T dohome_hal_wifi_get_connect_status(void){
	/**
	  WM_WIFI_DISCONNECTED - Disconnected state 
	  WM_WIFI_SCANNING     - Scanning for a network  
	  WM_WIFI_JOINING      - Trying to join with a BSS/SSID 
	  WM_WIFI_JOINED       - All authentication completed 
	 */
    int stat = tls_wifi_get_state();
	if (stat == WM_WIFI_JOINED) {
		return 1;
	}
    return 0;
}

void dohome_hal_wifi_init(void) {

    DOHOME_LOG_D("dohome_wifi_init");

}
DOHOME_STATIC void cb_scan_item_parse(struct wifi_mgmr_ap_item *env, long unsigned int *param1, struct wifi_mgmr_ap_item *item)
{
    
}

DOHOME_STATIC u8 scan_buff[2000] = {0};
DOHOME_STATIC u8 ap_list_buff[sizeof(dohome_ap_info_t)*SCAN_MAX_AP] = {0};
DOHOME_STATIC void cb_scan_complete(void){
    //char *buf = NULL;
    //u32 buflen;
    int i = 0, j = 0;
    int err = 0;
    u8 ssid[33];
    struct tls_scan_bss_t *wsr;
    struct tls_bss_info_t *bss_info;
	
    //buflen = 2000;
    //buf = tls_mem_alloc(buflen);
    //if (!buf) {
	//	DOHOME_LOG_E("scan Malloc Fail1!");
    //    goto end;
    //}

	memset(scan_buff, 0, 2000);
    err = tls_wifi_get_scan_rslt((u8 *)scan_buff, 2000);
    if (err) {
		DOHOME_LOG_E("scan Malloc Fail2!");
        goto end;
    }

    wsr = (struct tls_scan_bss_t *)scan_buff;
    bss_info = (struct tls_bss_info_t *)(scan_buff + 8);

    dohome_ap_info_t *ap_list = (dohome_ap_info_t *)ap_list_buff, *ap_list_ptr = NULL;
	//ap_list = tls_mem_alloc(sizeof(dohome_ap_info_t)*SCAN_MAX_AP);
    //if (ap_list == NULL){
    //    DOHOME_LOG_E("scan Malloc Fail!");
    //    goto end;
    //}
	memset(ap_list, 0, sizeof(dohome_ap_info_t)*SCAN_MAX_AP);
	ap_list_ptr = ap_list;

    for(i = 0; i < wsr->count; i++)
    {
		ap_list_ptr[i].rssi = (signed char)bss_info->rssi;
		ap_list_ptr[i].channel = bss_info->channel;
		ap_list_ptr[i].ssid_len = bss_info->ssid_len;
		memcpy(ap_list_ptr[i].ssid, bss_info->ssid, bss_info->ssid_len);
		memcpy(ap_list_ptr[i].bssid, bss_info->bssid, 6);
        bss_info ++;
		ap_list_ptr++; 
    }

	if(_doit_wifi_csan_cb){
        _doit_wifi_csan_cb(ap_list, wsr->count);
    }
end:
    //if(buf) {
    //    tls_mem_free(buf);
	//	buf = NULL;
    //}
	//if (ap_list) {
	//	tls_mem_free(ap_list);
	//	ap_list = NULL;
	//}
	DOHOME_LOG_D("scan result end\n");
}

dohome_op_ret dohome_hal_wifi_scan_start(dohome_wifi_csan_cb_t csan_cb){
	if(csan_cb == 0){
        return OPRT_OK;
    }
    _doit_wifi_csan_cb = csan_cb;
	tls_wifi_scan_result_cb_register(cb_scan_complete);
    int res = tls_wifi_scan(); 
    return OPRT_OK;
}
void dohome_hal_wifi_set_sleep_flag(DOHOME_UINT8_T flag)
{
    printf("dohome_hal_wifi_set_sleep_flag not support now\r\n");
}

dohome_op_ret dohome_hal_wifi_get_connect_rssi(DOHOME_INT8_T *rssi){
    *rssi = -10; //test
    return OPRT_OK;
}

